﻿using Microsoft.SqlServer.Server;
using SketchUpAPI.NET.Enums;
using SketchUpAPI.NET.SketchUp.Exception;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace SketchUpAPI.NET.Objects
{
    /// <summary>
    /// 面
    /// </summary>
    /// <remarks> 对 SketchUpAPI 中的 SUFaceRef 的包装</remarks>
    public class Face : DrawingElement
    {
        #region API 函数
        /// <summary>
        /// 创建面
        /// </summary>
        /// <param name="face"></param>
        /// <param name="vertices">顶点</param>
        /// <param name="outer_loop"><see cref="LoopInput"/> 环</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceCreate(out IntPtr face, Point3D[] vertices, IntPtr outer_loop);

        /// <summary>
        /// 创建一个简单面
        /// </summary>
        /// <param name="face"></param>
        /// <param name="vertices3d">顶点</param>
        /// <param name="len">顶点个数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceCreateSimple(out IntPtr face, Point3D[] vertices3d, long len);

        /// <summary>
        /// 获取面的法向
        /// </summary>
        /// <param name="face"></param>
        /// <param name="normal">法向</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetNormal(IntPtr face, ref Vector3D normal);

        /// <summary>
        /// 释放面
        /// </summary>
        /// <param name="face"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceRelease(ref IntPtr face);

        /// <summary>
        /// 获取边缘个数
        /// </summary>
        /// <param name="face"></param>
        /// <param name="count">返回，边缘个数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetNumEdges(IntPtr face, out long count);

        /// <summary>
        /// 获取全部边缘
        /// </summary>
        /// <param name="face"></param>
        /// <param name="len">边缘个数</param>
        /// <param name="edges"><see cref="Edge"/>[] 全部边缘</param>
        /// <param name="realcount">返回，真实边缘个数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetEdges(IntPtr face, long len, IntPtr[] edges, out long realcount);

        /// <summary>
        /// 获取使用到的边缘个数
        /// </summary>
        /// <param name="face"></param>
        /// <param name="count">返回，用到的边缘个数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetNumEdgeUses(IntPtr face, out long count);

        /// <summary>
        /// 获取全部的边缘使用状态
        /// </summary>
        /// <param name="face"></param>
        /// <param name="len">边缘使用个数</param>
        /// <param name="edges">全部边缘使用状态 <see cref="EdgeUse"/>[]</param>
        /// <param name="count">真实使用个数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetEdgeUses(IntPtr face, long len, IntPtr[] edges, out long count);

        /// <summary>
        /// 获取面所在的平面
        /// </summary>
        /// <param name="face"></param>
        /// <param name="plane"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetPlane(IntPtr face, ref Plane3D plane);

        /// <summary>
        /// 获取面包含的顶点个数
        /// </summary>
        /// <param name="face"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetNumVertices(IntPtr face, out long count);

        /// <summary>
        /// 获取面包含的顶点
        /// </summary>
        /// <param name="face"></param>
        /// <param name="len">个数</param>
        /// <param name="vertices"> <see cref="Vertex"/>[] 保存全部顶点</param>
        /// <param name="realcount">真实个数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetVertices(IntPtr face, long len, IntPtr[] vertices, out long realcount);

        /// <summary>
        /// 获取面的外边缘
        /// </summary>
        /// <param name="face"></param>
        /// <param name="loop"><see cref="Loop"/> 外边缘</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetOuterLoop(IntPtr face, out IntPtr loop);

        /// <summary>
        /// 获取内边缘的个数
        /// </summary>
        /// <param name="face"></param>
        /// <param name="count">总数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetNumInnerLoops(IntPtr face, out long count);

        /// <summary>
        /// 获取全部内环
        /// </summary>
        /// <param name="face"></param>
        /// <param name="len">总数</param>
        /// <param name="loops"><see cref="Loop"/>[] 保存全部内环</param>
        /// <param name="count">真实个数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetInnerLoops(IntPtr face, long len, IntPtr[] loops, out long count);

        /// <summary>
        /// 添加内环
        /// </summary>
        /// <param name="face"></param>
        /// <param name="vertices3d">内环包含的全部顶点</param>
        /// <param name="loop"><see cref="LoopInput"/> 内环</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceAddInnerLoop(IntPtr face, Point3D[] vertices3d, IntPtr loop);

        /// <summary>
        /// 获取面上的开口数
        /// </summary>
        /// <param name="face"></param>
        /// <param name="count">开口数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetNumOpenings(IntPtr face, out long count);

        /// <summary>
        /// 获取面的全部开口
        /// </summary>
        /// <param name="face"></param>
        /// <param name="len">开口个数</param>
        /// <param name="openings"><see cref="Opening"/>[] 保存全部开口</param>
        /// <param name="realcount">真实个数</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetOpenings(IntPtr face, long len, IntPtr[] openings, out long realcount);

        /// <summary>
        /// 获取正面材质
        /// </summary>
        /// <param name="face"></param>
        /// <param name="material"><see cref="Material"/> 材质</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetFrontMaterial(IntPtr face, ref IntPtr material);

        /// <summary>
        /// 设置正面材质
        /// </summary>
        /// <param name="face"></param>
        /// <param name="material"><see cref="Material"/> 材质</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceSetFrontMaterial(IntPtr face, IntPtr material);

        /// <summary>
        /// 获取背面材质
        /// </summary>
        /// <param name="face"></param>
        /// <param name="material"><see cref="Material"/> 材质</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetBackMaterial(IntPtr face, ref IntPtr material);

        /// <summary>
        ///设置背面材质
        /// </summary>
        /// <param name="face"></param>
        /// <param name="material"><see cref="Material"/> 材质</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceSetBackMaterial(IntPtr face, IntPtr material);

        /// <summary>
        /// 判断正面材质是否进行仿射变换
        /// </summary>
        /// <param name="face"></param>
        /// <param name="is_affine"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceIsFrontMaterialAffine(IntPtr face, out bool is_affine);

        /// <summary>
        /// 判断背面材质是否进行仿射变换
        /// </summary>
        /// <param name="face"></param>
        /// <param name="is_affine"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceIsBackMaterialAffine(IntPtr face, out bool is_affine);

        /// <summary>
        /// 计算面的面积
        /// </summary>
        /// <remarks>考虑内环和洞口剪切</remarks>
        /// <param name="face"></param>
        /// <param name="area"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetArea(IntPtr face, out double area);

        /// <summary>
        /// 计算经过变换后的面积
        /// </summary>
        /// <param name="face"></param>
        /// <param name="transform">变换</param>
        /// <param name="area"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetAreaWithTransform(IntPtr face, Transformation transform, out double area);

        /// <summary>
        /// 是否是复合面，既包含内环和洞口
        /// </summary>
        /// <param name="face"></param>
        /// <param name="is_complex"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceIsComplex(IntPtr face, out bool is_complex);

        /// <summary>
        /// 获取面的 <see cref="UVHelper"/>
        /// </summary>
        /// <param name="face"></param>
        /// <param name="front"></param>
        /// <param name="back"></param>
        /// <param name="texture_writer"><see cref="TextureWriter"/> 纹理保存器</param>
        /// <param name="uv_helper"><see cref="UVHelper"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetUVHelper(IntPtr face, bool front, bool back, IntPtr texture_writer, out IntPtr uv_helper);

        /// <summary>
        /// 使用纹理句柄获取 <see cref="UVHelper"/>
        /// </summary>
        /// <param name="face"></param>
        /// <param name="front"></param>
        /// <param name="back"></param>
        /// <param name="texture_writer"><see cref="TextureWriter"/></param>
        /// <param name="textureHandle"></param>
        /// <param name="uv_helper"><see cref="UVHelper"/></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetUVHelperWithTextureHandle(IntPtr face, bool front, bool back, IntPtr texture_writer, long textureHandle, out IntPtr uv_helper);

        /// <summary>
        /// 获取面链接的 <see cref="DrawingElement"/> 个数
        /// </summary>
        /// <param name="face"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetNumAttachedDrawingElements(IntPtr face, out long count);

        /// <summary>
        /// 获取与面链接的 <see cref="DrawingElement"/>
        /// </summary>
        /// <param name="face"></param>
        /// <param name="len"></param>
        /// <param name="elems"><see cref="DrawingElement"/>[] 保存物体</param>
        /// <param name="realcount"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetAttachedDrawingElements(IntPtr face, long len, IntPtr[] elems, out long realcount);

        /// <summary>
        /// 反转面的方向
        /// </summary>
        /// <param name="face"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceReverse(IntPtr face);

        /// <summary>
        /// 获取某个点的UV平铺的世界坐标和UV坐标
        /// </summary>
        /// <remarks>返回的 <paramref name="points"/> 和 <paramref name="uv_coords"/> 可直接用于 <see cref="MaterialInput"/></remarks>
        /// <param name="face"></param>
        /// <param name="reference">点</param>
        /// <param name="front">是否获取正面</param>
        /// <param name="points">世界坐标，四个点</param>
        /// <param name="uv_coords">UV坐标，四个点</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetUVTileAt(IntPtr face, Point3D reference, bool front, ref Point3D[] points, ref Point2D[] uv_coords);

        /// <summary>
        /// 判断面是否使用定位纹理
        /// </summary>
        /// <remarks>纹理在不使用默认纹理坐标时就是进行定位的。
        /// <para>当用户使用 材质 工具从材质浏览器中选择并使用材质时，它使用的是默认纹理坐标；如果用户使用 定位纹理工具，它就是定位的。</para></remarks>
        /// <param name="face"></param>
        /// <param name="front"></param>
        /// <param name="is_positioned"></param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceIsTexturePositioned(IntPtr face, bool front, out bool is_positioned);

        /// <summary>
        /// 清除纹理定位
        /// </summary>
        /// <param name="face"></param>
        /// <param name="front">是否是正面</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceClearTexturePosition(IntPtr face, bool front);

        /// <summary>
        /// 判断面是否有纹理投影
        /// </summary>
        /// <param name="face"></param>
        /// <param name="front">true：判断正面；false：判断反面</param>
        /// <param name="is_projected">返回，是否有纹理投影</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceIsTextureProjected(IntPtr face, bool front, out bool is_projected);

        /// <summary>
        /// 获取纹理投影方向
        /// </summary>
        /// <param name="face"></param>
        /// <param name="front">true：获取正面；false：获取反面</param>
        /// <param name="vector">返回，方向</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceGetTextureProjection(IntPtr face, bool front, ref Vector3D vector);

        /// <summary>
        /// 清除纹理投影
        /// </summary>
        /// <param name="face"></param>
        /// <param name="front">true：清除正面；false：清除反面</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFaceClearTextureProjection(IntPtr face, bool front);

        /// <summary>
        /// 获取材质定位关系
        /// </summary>
        /// <param name="face"></param>
        /// <param name="front"></param>
        /// <param name="mapping">材质定位</param>
        /// <returns></returns>
        [DllImport(LIB)]
        static extern SUResult SUFacePositionMaterial(IntPtr face, bool front, ref MaterialInput mapping);
        #endregion

        /// <summary>
        /// 获取面所在平面
        /// </summary>
        public Plane3D Plane
        {
            get
            {
                Plane3D p = new Plane3D();
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetPlane(Id, ref p));
                return p;
            }
        }

        /// <summary>
        /// 面的法向
        /// </summary>
        public Vector3D Normal
        {
            get
            {
                Vector3D v = new Vector3D();
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetNormal(Id, ref v));
                return v;
            }
        }

        /// <summary>
        /// 全部边
        /// </summary>
        public List<Edge> Edges
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetNumEdges(Id, out long count));
                IntPtr[] ptrs = new IntPtr[count];
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetEdges(Id, count, ptrs, out long realcount));
                return ptrs.Select(pt => new Edge(pt)).ToList();
            }
        }

        /// <summary>
        /// 全部使用的边
        /// </summary>
        public List<EdgeUse> EdgeUses
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetNumEdgeUses(Id, out long count));
                IntPtr[] ptrs = new IntPtr[count];
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetEdgeUses(Id, count, ptrs, out long realcount));
                return ptrs.Select(id => new EdgeUse(id)).ToList();
            }
        }

        /// <summary>
        /// 全部顶点
        /// </summary>
        public List<Vertex> Vertices
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetNumVertices(Id, out long count));
                IntPtr[] pts = new IntPtr[count];
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetVertices(Id, count, pts, out long realcount));
                return pts.Select(i => new Vertex(i)).ToList();
            }
        }

        /// <summary>
        /// 外圈
        /// </summary>
        public Loop OuterLoop
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetOuterLoop(Id, out IntPtr loop));
                return new Loop(loop);
            }
        }

        /// <summary>
        /// 内圈
        /// </summary>
        public List<Loop> InnerLoops
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetNumInnerLoops(Id, out long count));
                IntPtr[] ptrs = new IntPtr[count];
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetInnerLoops(Id, count, ptrs, out long realcount));
                return ptrs.Select(i => new Loop(i)).ToList();
            }
        }

        /// <summary>
        /// 获取开口
        /// </summary>
        public List<Opening> Openings
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetNumOpenings(Id, out long count));
                IntPtr[] ptrs = new IntPtr[count];
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetOpenings(Id, count, ptrs, out long realcount));
                return ptrs.Select(i => new Opening(i)).ToList();
            }
        }

        /// <summary>
        /// 正面材质
        /// </summary>
        public Material FrontMaterial
        {
            get
            {
                Material m = new Material();
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetFrontMaterial(Id, ref m.Id));
                return m;
            }
            set
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceSetFrontMaterial(Id, value.Id));
            }
        }

        /// <summary>
        /// 正面材质是否进行了仿射变换
        /// </summary>
        public bool IsFrontMaterialAffine
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceIsFrontMaterialAffine(Id, out bool a));
                return a;
            }
        }

        /// <summary>
        /// 正面材质定位
        /// </summary>
        public MaterialInput FrontMaterialPosition
        {
            get
            {
                MaterialInput m = new MaterialInput();
                SketchUpExceptionHelper.ThrowSUResult(SUFacePositionMaterial(Id, true, ref m));
                return m;
            }
        }

        /// <summary>
        /// 判断正面面是否使用定位纹理
        /// </summary>
        /// <remarks>纹理在不使用默认纹理坐标时就是进行定位的。
        /// <para>当用户使用 材质 工具从材质浏览器中选择并使用材质时，它使用的是默认纹理坐标；如果用户使用 定位纹理工具，它就是定位的。</para></remarks>
        public bool IsFrontTexturePositioned
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceIsTexturePositioned(Id, true, out bool b));
                return b;
            }
        }

        /// <summary>
        /// 正面是否有纹理投影
        /// </summary>
        public bool IsFrontTextureProjected
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceIsTextureProjected(Id, true, out bool b));
                return b;
            }
        }

        /// <summary>
        /// 正面纹理投影方向
        /// </summary>
        public Vector3D FrontTextureProjection
        {
            get
            {
                Vector3D v = new Vector3D();
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetTextureProjection(Id, true, ref v));
                return v;
            }
        }

        /// <summary>
        /// 背面材质
        /// </summary>
        public Material BackMaterial
        {
            get
            {
                Material m = new Material();
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetBackMaterial(Id, ref m.Id));
                return m;
            }
            set
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceSetBackMaterial(Id, value.Id));
            }
        }

        /// <summary>
        /// 背面材质是否进行了仿射变换
        /// </summary>
        public bool IsBackMaterialAffine
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceIsBackMaterialAffine(Id, out bool a));
                return a;
            }
        }

        /// <summary>
        /// 背面材质定位
        /// </summary>
        public MaterialInput BackMaterialPosition
        {
            get
            {
                MaterialInput m = new MaterialInput();
                SketchUpExceptionHelper.ThrowSUResult(SUFacePositionMaterial(Id, false, ref m));
                return m;
            }
        }

        /// <summary>
        /// 判断正面面是否使用定位纹理
        /// </summary>
        /// <remarks>纹理在不使用默认纹理坐标时就是进行定位的。
        /// <para>当用户使用 材质 工具从材质浏览器中选择并使用材质时，它使用的是默认纹理坐标；如果用户使用 定位纹理工具，它就是定位的。</para></remarks>
        public bool IsBackTexturePositioned
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceIsTexturePositioned(Id, false, out bool b));
                return b;
            }
        }

        /// <summary>
        /// 背面是否有纹理投影
        /// </summary>
        public bool IsBackTextureProjected
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceIsTextureProjected(Id, false, out bool b));
                return b;
            }
        }

        /// <summary>
        /// 背面纹理投影方向
        /// </summary>
        public Vector3D BackTextureProjection
        {
            get
            {
                Vector3D v = new Vector3D();
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetTextureProjection(Id, false, ref v));
                return v;
            }
        }

        /// <summary>
        /// 连接的物体
        /// </summary>
        public List<DrawingElement> AttachedDrawingElements
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetNumAttachedDrawingElements(Id, out long count));
                IntPtr[] pts = new IntPtr[count];
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetAttachedDrawingElements(Id, count, pts, out long realcount));
                return pts.Select(i => new DrawingElement(i)).ToList();
            }
        }

        /// <summary>
        /// 面积
        /// </summary>
        /// <remarks>去除内圈和洞口</remarks>
        public double Area
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceGetArea(Id, out double a));
                return a;
            }
        }

        /// <summary>
        /// 是否时复杂面，既包含内圈和洞口
        /// </summary>
        public bool IsComplex
        {
            get
            {
                SketchUpExceptionHelper.ThrowSUResult(SUFaceIsComplex(Id, out bool b));
                return b;
            }
        }

        internal Face(IntPtr id) => Id = id;

        /// <summary>
        /// 使用顶点和环数据创建
        /// </summary>
        /// <param name="vertices"></param>
        /// <param name="outer_loop"></param>
        /// <returns></returns>
        public static Face Create(Point3D[] vertices, LoopInput outer_loop)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUFaceCreate(out IntPtr face, vertices, outer_loop.Id));
            return new Face(face);
        }

        /// <summary>
        /// 使用顶点创建一个不带洞口的面
        /// </summary>
        /// <param name="vertices">顶点</param>
        /// <returns></returns>
        public static Face Create(Point3D[] vertices)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUFaceCreateSimple(out IntPtr face, vertices, vertices.Length));
            return new Face(face);
        }

        /// <summary>
        /// 获取在某个变换下的面积
        /// </summary>
        /// <param name="transformation"></param>
        /// <returns></returns>
        public double GetAreaWithTransform(Transformation transformation)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUFaceGetAreaWithTransform(Id, transformation, out double a));
            return a;
        }

        /// <summary>
        /// 获取贴图UV帮助类
        /// </summary>
        /// <param name="writer">纹理保存器</param>
        /// <param name="front">是否获取正面材质</param>
        /// <param name="back">是否获取背面材质</param>
        /// <returns></returns>
        public UVHelper GetUVHelper(TextureWriter writer, bool front, bool back)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUFaceGetUVHelper(Id, front, back, writer.Id, out IntPtr uv));
            return new UVHelper(uv);
        }

        /// <summary>
        /// 获取UV帮助类
        /// </summary>
        /// <param name="writer"></param>
        /// <param name="front"></param>
        /// <param name="back"></param>
        /// <param name="imageHandle">纹理图片的句柄</param>
        /// <returns></returns>
        public UVHelper GetUVHelperWithTextureHandle(TextureWriter writer, bool front, bool back, int imageHandle)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUFaceGetUVHelperWithTextureHandle(Id, front, back, writer.Id, imageHandle, out IntPtr uv));
            return new UVHelper(uv);
        }

        /// <summary>
        /// 添加内环
        /// </summary>
        /// <param name="points"></param>
        /// <param name="loopSet"></param>
        public void AddInnerLoop(Point3D[] points, LoopInput loopSet)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUFaceAddInnerLoop(Id, points, loopSet.Id));
        }

        /// <summary>
        /// 反转面的方向
        /// </summary>
        public void Reverse()
        {
            SketchUpExceptionHelper.ThrowSUResult(SUFaceReverse(Id));
        }

        /// <summary>
        /// 获取某个点的uv坐标
        /// </summary>
        /// <remarks>返回的 <paramref name="points"/> 和 <paramref name="uv_coords"/> 可直接用于 <see cref="MaterialInput"/></remarks>
        /// <param name="point"></param>
        /// <param name="front_or_back">true：正面；false：背面</param>
        /// <param name="worldPoint"></param>
        /// <param name="uvCoords"></param>
        public void GetUVTileAtPoint(Point3D point, bool front_or_back, out Point3D[] worldPoint, out Point2D[] uvCoords)
        {
            worldPoint = new Point3D[4];
            uvCoords = new Point2D[4];
            SketchUpExceptionHelper.ThrowSUResult(SUFaceGetUVTileAt(Id, point, front_or_back, ref worldPoint, ref uvCoords));
        }

        /// <summary>
        /// 清除纹理定位
        /// </summary>
        /// <param name="front_or_back">true：正面；false：背面</param>
        public void ClearTexturePosition(bool front_or_back)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUFaceClearTexturePosition(Id, front_or_back));
        }

        /// <summary>
        /// 清除纹理投影
        /// </summary>
        /// <param name="front_or_back">true：正面；false：背面</param>
        public void ClearTextureProjection(bool front_or_back)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUFaceClearTextureProjection(Id, front_or_back));
        }

        public override void Dispose()
        {
            SketchUpExceptionHelper.ThrowSUResult(SUFaceRelease(ref Id));
        }
    }
}